/**
 *  CloudEdit- Editor colaborativo peer-to-peer
 *  Author: Miguel Souto Bartolomé
 *  Web: http://code.google.com/p/cloudedit/
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.google.gwt.cloudedit.server;

import java.util.ArrayList;
import java.util.Iterator;

import com.google.gwt.cloudedit.server.auxiliares.ArchivoSerializable;
import com.google.gwt.cloudedit.server.auxiliares.ListadoSerializable;
import com.google.gwt.cloudedit.server.exceptions.ExcepcionArchivo;
import com.google.gwt.cloudedit.shared.DatosArchivo;
import com.google.gwt.cloudedit.shared.DatosListado;
import easypastry.dht.DHTHandler;
import easypastry.dht.DHTException;
import easypastry.core.PastryKernel;
import easypastry.util.Utilities;

/**
 * La clase GestionArchivos se encarga de facilitar las tareas de introducción
 * y recuperación de datos en una red Pastry de tabla Hash distribuida.
 * 
 * @author Miguel Souto Bartolomé
 * @version 4.0  
 */
public class GestionArchivos {

	/** El controlador de DHT. */
	private DHTHandler dht;	

	/**
	 * Instancia una nueva gestión de archivos.
	 *
	 * @param context el identificador del contexto del DHT
	 * @throws DHTException
	 */
	public GestionArchivos(String context) throws DHTException {
		dht = PastryKernel.getDHTHandler(Utilities.generateStringHash(context));
	}

	/**
	 * Recupera un archivo de la red Pastry.
	 *
	 * @param id el identificador único del archivo
	 * @return el archivo
	 * @throws ExcepcionArchivo
	 */
	public DatosArchivo getFile(String id) throws ExcepcionArchivo {

		try {
			ArchivoSerializable file = (ArchivoSerializable) dht.get(id);
			if (file == null) {
				throw new ExcepcionArchivo("El archivo no existe");
			}
			DatosArchivo archivoDatos = toDatosArchivo(file);			
			return archivoDatos;

		} catch (DHTException e) {
			System.out.println("Error al abrir el archivo");
			throw new ExcepcionArchivo(e.getMessage());
		}
	}

	/**
	 * Introduce o modifica un archivo en la red DHT.
	 *
	 * @param file el nuevo archivo o archivo a actualizar
	 * @throws ExcepcionArchivo
	 */
	public void setFile(DatosArchivo file) throws ExcepcionArchivo {
		try {
			dht.put(file.getId(), toArchivoSerializable(file));

		} catch (DHTException e) {
			throw new ExcepcionArchivo(e.getMessage());
		}
	}
	
	/**
	 * Recupera el listado con los archivos presentes en la red DHT.
	 *
	 * @return la lista
	 * @throws ExcepcionArchivo
	 */
	
	@SuppressWarnings("unchecked")
	public ArrayList<DatosListado> getList() throws ExcepcionArchivo {

		try {
			ArrayList<ListadoSerializable> listado = (ArrayList<ListadoSerializable>) dht.get(Utilities.generateStringHash("CloudEditListado"));
			if (listado == null) {
				System.out.println("El listado no existe");
				throw new ExcepcionArchivo("El listado no existe");
			}
			ArrayList<DatosListado> list = toDatosListado(listado);
			return list;

		} catch (DHTException e) {
			System.out.println("Error al abrir el listado");
			throw new ExcepcionArchivo(e.getMessage());
		}
	}

	/**
	 * Introduce o modifica la lista de los archivos presentes
	 * en la red DHT.
	 *
	 * @param listado la nueva lista o lista actualizada
	 * @throws ExcepcionArchivo
	 */
	public void setList(ArrayList<DatosListado> listado) throws ExcepcionArchivo {
		try {
			if (listado.isEmpty()) {
				dht.put(Utilities.generateStringHash("CloudEditListado"), new ArrayList<ListadoSerializable>());
			} else {
				dht.put(Utilities.generateStringHash("CloudEditListado"), toSerializableListado(listado));
			}
		} catch (DHTException e) {
			throw new ExcepcionArchivo(e.getMessage());
		}
	}
	
	/**
	 * Convierte un archivo serializable normal en serializable GWT.
	 * @param archivo archivo serializable normal
	 * @return archivo serializable GWT
	 */
	private DatosArchivo toDatosArchivo (ArchivoSerializable archivo) {
		return new DatosArchivo(archivo.getId(), archivo.getName(), archivo.getCreated(), archivo.getModified(), archivo.getContent(), archivo.getIp());
	}
	
	/**
	 * Convierte un archivo serializable GWT en serializable normal.
	 * @param archivo archivo serializable GWT
	 * @return archivo serializable normal
	 */
	private ArchivoSerializable toArchivoSerializable (DatosArchivo archivo) {
		return new ArchivoSerializable(archivo.getId(), archivo.getName(), archivo.getCreated(), archivo.getModified(), archivo.getContent(), archivo.getIp());
	}
	
	/**
	 * Convierte un elemento de listado serializable normal en serializable GWT.
	 * @param elemento elemento serializable normal
	 * @return elemento serializable GWT
	 */
	private DatosListado toDatos (ListadoSerializable elemento) {
		return new DatosListado(elemento.getId(), elemento.getName(), elemento.getCreated(), elemento.getSize());
	}
	
	/**
	 * Convierte un elemento de listado serializable GWT en serializable normal.
	 * @param elemento elemento serializable GWT
	 * @return elemento serializable normal
	 */
	private ListadoSerializable toSerializable (DatosListado elemento) {
		return new ListadoSerializable(elemento.getId(), elemento.getName(), elemento.getCreated(), elemento.getSize());
	}
	
	/**
	 * Convierte un  listado serializable normal en serializable GWT
	 * @param listado listado serializable normal
	 * @return listado serializable GWT
	 */
	private ArrayList<DatosListado> toDatosListado (ArrayList<ListadoSerializable> listado) {
		ArrayList<DatosListado> listadoAux = new ArrayList<DatosListado>();
		Iterator<ListadoSerializable> it = listado.iterator();
		while (it.hasNext()) {
			ListadoSerializable elemento = it.next();
			listadoAux.add(this.toDatos(elemento));
			
		}
		return listadoAux;
	}
	
	/**
	 * Convierte un  listado serializable GWT en serializable normal
	 * @param listado listado serializable GWT
	 * @return listado serializable normal
	 */
	private ArrayList<ListadoSerializable> toSerializableListado (ArrayList<DatosListado> listado) {
		ArrayList<ListadoSerializable> listadoAux = new ArrayList<ListadoSerializable>();
		Iterator<DatosListado> it = listado.iterator();
		while (it.hasNext()) {
			DatosListado elemento = it.next();
			listadoAux.add(this.toSerializable(elemento));
			
		}
		return listadoAux;
	}	
}